package cn.growthgate.fgo.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;

import cn.growthgate.fgo.common.base.BaseServiceImpl;
import cn.growthgate.fgo.common.base.BaseVo;
import cn.growthgate.fgo.entity.Item;
import cn.growthgate.fgo.entity.MyServant;
import cn.growthgate.fgo.entity.Servant;
import cn.growthgate.fgo.entity.enums.ServantGet;
import cn.growthgate.fgo.entity.enums.ServantItemType;
import cn.growthgate.fgo.entity.enums.ServantStage;
import cn.growthgate.fgo.entity.vo.MyItemVo;
import cn.growthgate.fgo.entity.vo.MyServantVo;
import cn.growthgate.fgo.mapper.MyServantMapper;
import cn.growthgate.fgo.service.IMyServantService;
import cn.growthgate.fgo.util.DateUtils;

/**
 * <p>
 * 我的从者 服务实现类
 * </p>
 *
 * @author GrowthGate
 * @since 2019-05-29
 */
@Service
public class MyServantServiceImpl extends BaseServiceImpl<MyServantMapper, MyServant> implements IMyServantService {

	/**
	 * 灵基再临消耗QP
	 */
	private int[][] stageQp = {
			{15000, 45000, 150000, 450000},
			{10000, 30000, 90000, 300000},
			{15000, 45000, 150000, 450000},
			{30000, 100000, 300000, 900000},
			{50000, 150000, 500000, 1500000},
			{100000, 300000, 1000000, 3000000}
	};

	/**
	 * 技能强化消耗QP
	 */
	private int[][] skillQp = {
			{20000, 40000, 120000, 160000, 400000, 500000, 1000000, 1200000, 2000000},
			{10000, 20000, 60000, 80000, 200000, 250000, 500000, 600000, 1000000},
			{20000, 40000, 120000, 160000, 400000, 500000, 1000000, 1200000, 2000000},
			{50000, 100000, 300000, 400000, 1000000, 1250000, 2500000, 3000000, 5000000},
			{100000, 200000, 600000, 800000, 2000000, 2500000, 5000000, 6000000, 10000000},
			{200000, 400000, 1200000, 1600000, 4000000, 5000000, 10000000, 12000000, 20000000}
	};

	/**
	 * 宝具强化消耗QP
	 */
	private int[][] npQp = {
			{10000, 20000, 40000, 80000},
			{5000, 10000, 20000, 40000},
			{10000, 20000, 40000, 80000},
			{20000, 40000, 80000, 160000},
			{40000, 80000, 160000, 320000},
			{80000, 160000, 320000, 640000}
	};

	/**
	 * 圣杯转临消耗QP
	 */
	private int[][] holyGrailQp = {
		{600000, 800000, 1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000},
		{400000, 600000, 800000, 1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000},
		{600000, 800000, 1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000},
		{1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000},
		{4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000},
		{9000000, 10000000, 11000000, 12000000, 13000000}
	};

	@Override
	public BaseVo<MyServant> transformVo(MyServant entity) {
		MyServantVo vo = new MyServantVo();
		vo.setId(entity.getId());
		vo.setServant(baseMapper.getServant(entity));
		vo.setStage(entity.getStage());
		vo.setHolyGrail(entity.getHolyGrail());
		vo.setLevel(entity.getLevel());
		vo.setNpLevel(entity.getNpLevel());
		vo.setSkill1(entity.getSkill1());
		vo.setSkill2(entity.getSkill2());
		vo.setSkill3(entity.getSkill3());
		vo.setFfHp(entity.getFfHp());
		vo.setFfAtk(entity.getFfAtk());
		vo.setHp(entity.getHp());
		vo.setAtk(entity.getAtk());
		vo.setBondLevel(entity.getBondLevel());
		vo.setBondValue(entity.getBondValue());
		vo.setDailyBond(entity.getDailyBond());
		vo.setGetDate(entity.getGetDate());
		if (entity.getGetDate() != null) {
			vo.setGetDays(DateUtils.getDiffDay(entity.getGetDate(), new Date()));
		}
		vo.setLastUpdateTime(entity.getLastUpdateTime());
		return vo;
	}

	@Override
	public Page<MyServant> selectJoinServant(Integer current, Integer size, String orderByField, Boolean isAsc,
			Wrapper<MyServant> wrapper) {
		Page<MyServant> page = constPage(current, size, orderByField, isAsc, wrapper, "ms");
		return page.setRecords(baseMapper.selectJoinServant(page, wrapper));
	}

	@Override
	public MyItemVo getUsedQp() {
		List<MyServant> myServants = selectAll();
		long usedTotal = 0;
		List<MyItemVo> usedItem = new ArrayList<>();
		for (MyServant myServant : myServants) {
			Servant servant = baseMapper.getServant(myServant);
			if (servant.getGets().contains(ServantGet.INIT)) {
				// 玛修只有技能强化使用QP，使用量以三星为准
				long total = 0;
				Integer skill1 = myServant.getSkill1();
				if (skill1 != null) {
					while (skill1 > 1) {
						total += skillQp[3][--skill1 - 1];
					}
				}
				Integer skill2 = myServant.getSkill2();
				if (skill2 != null) {
					while (skill2 > 1) {
						total += skillQp[3][--skill2 - 1];
					}
				}
				Integer skill3 = myServant.getSkill3();
				if (skill3 != null) {
					while (skill3 > 1) {
						total += skillQp[3][--skill3 - 1];
					}
				}
				if (total > 0) {
					List<MyItemVo> detail = Arrays.asList(new MyItemVo("技能", total));
					MyItemVo myItemVo = new MyItemVo(servant.getName(), servant.getAvatar(), total, detail);
					// 添加到最终结果中
					usedTotal += total;
					usedItem.add(myItemVo);
				}
			} else {
				long total = 0;
				List<MyItemVo> detail = new ArrayList<>();
				// 灵基再临
				ServantStage stage = myServant.getStage();
				if (stage != null) {
					int stageValue = (int) stage.getValue();
					long stageNumber = 0;
					while (stageValue > 0) {
						int number = stageQp[servant.getStar()][--stageValue];
						stageNumber += number;
					}
					if (stageNumber > 0) {
						total += stageNumber;
						detail.add(new MyItemVo("灵基", stageNumber));
					}
				}
				// 技能强化
				long skillNumber = 0;
				Integer skill1 = myServant.getSkill1();
				if (skill1 != null) {
					while (skill1 > 1) {
						skillNumber += skillQp[servant.getStar()][--skill1 - 1];
					}
				}
				Integer skill2 = myServant.getSkill2();
				if (skill2 != null) {
					while (skill2 > 1) {
						skillNumber += skillQp[servant.getStar()][--skill2 - 1];
					}
				}
				Integer skill3 = myServant.getSkill3();
				if (skill3 != null) {
					while (skill3 > 1) {
						skillNumber += skillQp[servant.getStar()][--skill3 - 1];
					}
				}
				if (skillNumber > 0) {
					total += skillNumber;
					detail.add(new MyItemVo("技能", skillNumber));
				}
				// 宝具强化
				Integer npLevel = myServant.getNpLevel();
				if (npLevel != null) {
					long npNumber = 0;
					while (npLevel > 1) {
						npNumber += npQp[servant.getStar()][--npLevel - 1];
					}
					if (npNumber > 0) {
						total += npNumber;
						detail.add(new MyItemVo("宝具", npNumber));
					}
				}
				// 圣杯转临
				Integer holyGrail = myServant.getHolyGrail();
				if (holyGrail != null) {
					long holyGrailNumber = 0;
					// 圣杯数量超过数组长度时，将圣杯数量设为数组长度
					holyGrail = Integer.min(holyGrail, holyGrailQp[servant.getStar()].length);
					while (holyGrail > 0) {
						holyGrailNumber += holyGrailQp[servant.getStar()][--holyGrail];
					}
					if (holyGrailNumber > 0) {
						total += holyGrailNumber;
						detail.add(new MyItemVo("圣杯", holyGrailNumber));
					}
				}
				if (total > 0) {
					MyItemVo myItemVo = new MyItemVo(servant.getName(), servant.getAvatar(), total, detail);
					// 添加到最终结果中
					usedTotal += total;
					usedItem.add(myItemVo);
				}
			}
		}
		// 对结果进行倒序排序
		Collections.sort(usedItem, Collections.reverseOrder());
		return new MyItemVo("QP", usedTotal, usedItem);
	}

	@Override
	public MyItemVo getTotalNeedQp() {
		List<MyServant> myServants = selectAll();
		long totalNeed = 0;
		List<MyItemVo> totalNeedItem = new ArrayList<>();
		for (MyServant myServant : myServants) {
			Servant servant = baseMapper.getServant(myServant);
			if (servant.getGets().contains(ServantGet.INIT)) {
				// 玛修只有技能强化使用QP，使用量以三星为准
				long total = 0;
				Integer skill1 = myServant.getSkill1();
				Integer toSkill1 = myServant.getToSkill1();
				if (skill1 != null && toSkill1 != null) {
					while (toSkill1 > skill1 && toSkill1 > 1) {
						total += skillQp[3][--toSkill1 - 1];
					}
				}
				Integer skill2 = myServant.getSkill2();
				Integer toSkill2 = myServant.getToSkill2();
				if (skill2 != null && toSkill2 != null) {
					while (toSkill2 > skill2 && toSkill2 > 1) {
						total += skillQp[3][--toSkill2 - 1];
					}
				}
				Integer skill3 = myServant.getSkill3();
				Integer toSkill3 = myServant.getToSkill3();
				if (skill3 != null && toSkill3 != null) {
					while (toSkill3 > skill3 && toSkill3 > 1) {
						total += skillQp[3][--toSkill3 - 1];
					}
				}
				if (total > 0) {
					List<MyItemVo> detail = Arrays.asList(new MyItemVo("技能", total));
					MyItemVo myItemVo = new MyItemVo(servant.getName(), servant.getAvatar(), total, detail);
					// 添加到最终结果中
					totalNeed += total;
					totalNeedItem.add(myItemVo);
				}
			} else {
				long total = 0;
				List<MyItemVo> detail = new ArrayList<>();
				// 灵基再临
				ServantStage stage = myServant.getStage();
				ServantStage toStage = myServant.getToStage();
				if (stage != null && toStage != null) {
					int stageValue = (int) stage.getValue();
					int toStageValue = (int) toStage.getValue();
					long stageNumber = 0;
					while (toStageValue > stageValue) {
						int number = stageQp[servant.getStar()][--toStageValue];
						stageNumber += number;
					}
					if (stageNumber > 0) {
						total += stageNumber;
						detail.add(new MyItemVo("灵基", stageNumber));
					}
				}
				// 技能强化
				long skillNumber = 0;
				Integer skill1 = myServant.getSkill1();
				Integer toSkill1 = myServant.getToSkill1();
				if (skill1 != null && toSkill1 != null) {
					while (toSkill1 > skill1 && toSkill1 > 1) {
						skillNumber += skillQp[servant.getStar()][--toSkill1 - 1];
					}
				}
				Integer skill2 = myServant.getSkill2();
				Integer toSkill2 = myServant.getToSkill2();
				if (skill2 != null && toSkill2 != null) {
					while (toSkill2 > skill2 && toSkill2 > 1) {
						skillNumber += skillQp[servant.getStar()][--toSkill2 - 1];
					}
				}
				Integer skill3 = myServant.getSkill3();
				Integer toSkill3 = myServant.getToSkill3();
				if (skill3 != null && toSkill3 != null) {
					while (toSkill3 > skill3 && toSkill3 > 1) {
						skillNumber += skillQp[servant.getStar()][--toSkill3 - 1];
					}
				}
				if (skillNumber > 0) {
					total += skillNumber;
					detail.add(new MyItemVo("技能", skillNumber));
				}
				if (total > 0) {
					MyItemVo myItemVo = new MyItemVo(servant.getName(), servant.getAvatar(), total, detail);
					// 添加到最终结果中
					totalNeed += total;
					totalNeedItem.add(myItemVo);
				}
			}
		}
		// 对结果进行倒序排序
		Collections.sort(totalNeedItem, Collections.reverseOrder());
		return new MyItemVo("QP", totalNeed, totalNeedItem);
	}

	@Override
	public Map<Long, MyItemVo> getUsedItem() {
		List<MyServant> myServants = selectAll();
		Map<Long, MyItemVo> result = baseMapper.selectAllItem().stream()
				.collect(Collectors.toMap(Item::getId, item -> new MyItemVo(item.getName(), 0, new ArrayList<>())));
		for (MyServant myServant : myServants) {
			Servant servant = baseMapper.getServant(myServant);
			Map<Long, MyItemVo> itemMap = new HashMap<>();
			// 灵基再临
			ServantStage stage = myServant.getStage();
			if (stage != null) {
				Map<Long, Map<String, Object>> servantItemMap = baseMapper.getServantItemNumber(servant.getId(),
						ServantItemType.STAGE, 0, (int) stage.getValue());
				servantItemMap.forEach((k, v) -> {
					long number = ((BigDecimal) v.get("number")).longValue();
					List<MyItemVo> detail = new ArrayList<>(Arrays.asList(new MyItemVo("灵基", number)));
					MyItemVo myItemVo = new MyItemVo(servant.getName(), servant.getAvatar(), number, detail);
					itemMap.put(k, myItemVo);
				});
			}
			// 技能强化
			Map<Long, Long> skillMap = new HashMap<>();
			putSkillMap(servant, skillMap, 0, myServant.getSkill1());
			putSkillMap(servant, skillMap, 0, myServant.getSkill2());
			putSkillMap(servant, skillMap, 0, myServant.getSkill3());
			skillMap.forEach((k, v) -> {
				MyItemVo myItemVo = itemMap.get(k);
				if (myItemVo != null) {
					myItemVo.setNumber(myItemVo.getNumber() + v);
					myItemVo.getDetail().add(new MyItemVo("技能", v));
				} else {
					List<MyItemVo> detail = Arrays.asList(new MyItemVo("技能", v));
					myItemVo = new MyItemVo(servant.getName(), servant.getAvatar(), v, detail);
					itemMap.put(k, myItemVo);
				}
			});
			itemMap.forEach((k, v) -> {
				// 添加到最终结果中
				MyItemVo resultItemVo = result.get(k);
				if (resultItemVo != null) {
					resultItemVo.setNumber(resultItemVo.getNumber() + v.getNumber());
					resultItemVo.getDetail().add(v);
				}
			});
		}
		// 对结果进行倒序排序
		result.values().forEach(usedItem -> Collections.sort(usedItem.getDetail(), Collections.reverseOrder()));
		return result;
	}

	@Override
	public Map<Long, MyItemVo> getTotalNeedItem() {
		List<MyServant> myServants = selectAll();
		Map<Long, MyItemVo> result = baseMapper.selectAllItem().stream()
				.collect(Collectors.toMap(Item::getId, item -> new MyItemVo(item.getName(), 0, new ArrayList<>())));
		for (MyServant myServant : myServants) {
			Servant servant = baseMapper.getServant(myServant);
			Map<Long, MyItemVo> itemMap = new HashMap<>();
			// 灵基再临
			ServantStage stage = myServant.getStage();
			ServantStage toStage = myServant.getToStage();
			if (stage != null && toStage != null) {
				Map<Long, Map<String, Object>> servantItemMap = baseMapper.getServantItemNumber(servant.getId(),
						ServantItemType.STAGE, (int) stage.getValue() + 1, (int) toStage.getValue());
				servantItemMap.forEach((k, v) -> {
					long number = ((BigDecimal) v.get("number")).longValue();
					List<MyItemVo> detail = new ArrayList<>(Arrays.asList(new MyItemVo("灵基", number)));
					MyItemVo myItemVo = new MyItemVo(servant.getName(), servant.getAvatar(), number, detail);
					itemMap.put(k, myItemVo);
				});
			}
			// 技能强化
			Map<Long, Long> skillMap = new HashMap<>();
			putSkillMap(servant, skillMap, myServant.getSkill1(), myServant.getToSkill1());
			putSkillMap(servant, skillMap, myServant.getSkill2(), myServant.getToSkill2());
			putSkillMap(servant, skillMap, myServant.getSkill3(), myServant.getToSkill3());
			skillMap.forEach((k, v) -> {
				MyItemVo myItemVo = itemMap.get(k);
				if (myItemVo != null) {
					myItemVo.setNumber(myItemVo.getNumber() + v);
					myItemVo.getDetail().add(new MyItemVo("技能", v));
				} else {
					List<MyItemVo> detail = Arrays.asList(new MyItemVo("技能", v));
					myItemVo = new MyItemVo(servant.getName(), servant.getAvatar(), v, detail);
					itemMap.put(k, myItemVo);
				}
			});
			itemMap.forEach((k, v) -> {
				// 添加到最终结果中
				MyItemVo resultItemVo = result.get(k);
				if (resultItemVo != null) {
					resultItemVo.setNumber(resultItemVo.getNumber() + v.getNumber());
					resultItemVo.getDetail().add(v);
				}
			});
		}
		// 对结果进行倒序排序
		result.values().forEach(totalNeed -> Collections.sort(totalNeed.getDetail(), Collections.reverseOrder()));
		return result;
	}

	/**
	 * 获取每个道具总数并放入skillMap中
	 * @param servant
	 * @param skillMap
	 * @param from
	 * @param to
	 */
	private void putSkillMap(Servant servant, Map<Long, Long> skillMap, Integer from, Integer to) {
		if (from != null && to != null) {
			Map<Long, Map<String, Object>> servantItemMap = baseMapper.getServantItemNumber(servant.getId(),
					ServantItemType.SKILL, from + 1, to);
			servantItemMap.forEach((k, v) -> {
				Long skillNumber = skillMap.get(k);
				if (skillNumber == null) {
					skillNumber = 0L;
				}
				skillMap.put(k, skillNumber + ((BigDecimal) v.get("number")).longValue());
			});
		}
	}

}
